package com.ruoyi.common.core.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.model.*;
import com.ruoyi.common.core.utils.bean.FileUrlData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Description:
 * @Author: bailun91
 * @FileName: OssUtils
 * @Date: 2021/07/02 3:44 下午
 */
@Component
public class OssUtils {

    @Autowired
    private Environment env;

    /**
     * aliyun : keyId && keySecret
     */
    private static String accessKeyId = "";
    private static String accessKeySecret = "";

    /**
     * aliyun oss : endpoint && bucketName
     */
    private static String endpoint = "";
    private static String bucketName = "";
    private static String profile = "";
    private static OSS ossClient;


    @PostConstruct
    public void config() {
        accessKeyId = env.getProperty("aliyun.accessKeyId");
        accessKeySecret = env.getProperty("aliyun.accessKeySecret");
        endpoint = env.getProperty("aliyun.oss.endpoint");
        bucketName = env.getProperty("aliyun.oss.bucketName");
        profile = env.getProperty("blogs.profile");

        // 初始化 OSS 客户端
        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    public static OSS getOssClient() {
        return ossClient;
    }

    /**
     * 检查bucketName 是否存在，不存在，立即创建
     *
     * @param oss
     */
    private static void checkBucketExist(OSS oss) {
        if (!oss.doesBucketExist(bucketName)) {
            oss.createBucket(bucketName);
        }
    }

    /**
     * 上传文件流到OSS
     *
     * @return 返回上传的路径
     */
    public static String uploadFileToOss(MultipartFile file, String path) throws IOException {
        String fileName = buildFileName(file.getOriginalFilename());
        String newFileName = String.format("%s-%s", DateUtils.dateTimeNow(), fileName);
        return uploadInputStreamToOss(new ByteArrayInputStream(file.getBytes()), path, newFileName, null, false);
    }

    /**
     * 上传文件流到OSS
     *
     * @return 返回上传的路径
     */
    public static String coverUploadFileToOss(MultipartFile file, String path) throws IOException {
        String fileName = file.getOriginalFilename();
        return uploadInputStreamToOss(new ByteArrayInputStream(file.getBytes()), path, fileName, null, false);
    }

    /**
     * 上传文件流到OSS
     *
     * @param inputStream 文件流
     * @param path        存储的文件目录
     * @param fileName    文件名
     * @return 返回上传的路径
     */
    public static String uploadInputStreamToOss(InputStream inputStream, String path, String fileName, ProgressListener progressListener, boolean async) {
        //创建对象
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        //检查bucket 是否存在
        checkBucketExist(ossClient);
        // 上传文件流。
        path += "/" + fileName;
        //上传
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path, inputStream);
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType("");
        putObjectRequest.setMetadata(meta);
        if (progressListener != null) {
            putObjectRequest.withProgressListener(progressListener);
        }
        if (async) {
            new Thread(() -> {
                ossClient.putObject(putObjectRequest);
                // 关闭OSSClient。
                ossClient.shutdown();
            }).start();
        } else {
            ossClient.putObject(putObjectRequest);
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        String urlStr = endpoint.replace("https://", "https://" + bucketName + ".");
        return urlStr + "/" + path;
    }


    private static String uploadInputStreamToOssCustom(String endpoints, String accessKeyIds, String accessKeySecrets, String bucketNames, InputStream inputStream, String path, String fileName, ProgressListener progressListener, boolean async) {
        //创建对象
        OSS ossClient = new OSSClientBuilder().build(endpoints, accessKeyIds, accessKeySecrets);
        //检查bucket 是否存在
        checkBucketExist(ossClient);
        // 上传文件流。
        path += "/" + fileName;
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        //上传
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketNames, path, inputStream);

        putObjectRequest.setMetadata(meta);

        if (progressListener != null) {
            putObjectRequest.withProgressListener(progressListener);
        }
        if (async) {
            new Thread(() -> {
                ossClient.putObject(putObjectRequest);
                // 关闭OSSClient。
                ossClient.shutdown();
            }).start();
        } else {
            ossClient.putObject(putObjectRequest);
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        String urlStr = endpoint.replace("https://", "https://" + bucketName + ".");
        return urlStr + "/" + path;
    }

    public static String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "";
    }


    /**
     * 删除oss中的资源
     *
     * @return
     */
    public static void deleteOssFile(String url) {

        String objectName = getFileNameFromUrl(url);
        String parentPath = getOssParentPathFromUrl(url);
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        boolean found = ossClient.doesObjectExist(bucketName, parentPath + "/" + objectName);
        if (found) {
            ossClient.deleteObject(bucketName, parentPath + "/" + objectName);
        }
        ossClient.shutdown();
    }


    /**
     * 获取oss中的全部资源
     *
     * @param keyPrefix 文件存储在oss的目录
     * @param maxKeys   分页参数，每页大小
     * @return
     */
    public static List<String> getOssFileList(String keyPrefix, int maxKeys) {
        ArrayList<String> list = new ArrayList<>();

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String nextMarker = null;
        ObjectListing objectListing;

        do {
            objectListing = ossClient.listObjects(new ListObjectsRequest(bucketName).
                    withPrefix(keyPrefix).withMarker(nextMarker).withMaxKeys(maxKeys));

            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
            for (OSSObjectSummary s : sums) {
                String key = s.getKey();
                String displayName = s.getOwner().getDisplayName();
                String[] split = key.split("/");
                if (split.length != 0) {
                    String name = Arrays.asList(split).get(split.length - 1);
                    if (!keyPrefix.equals(name)) {
                        String bucketDomain = endpoint.substring(8, endpoint.length());
                        name = "https://" + bucketName + "." + bucketDomain + "/" + keyPrefix + "/" + name;
                        list.add(name);
                    }
                }
            }
            nextMarker = objectListing.getNextMarker();

        } while (objectListing.isTruncated());

        ossClient.shutdown();
        return list;
    }

    private static boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    public static String getFileNameFromUrl(String url) {
        if (!StringUtils.isEmpty(url)) {
            String[] split = url.split("/");
            if (split.length != 0) {
                List<String> asList = Arrays.asList(split);
                return asList.get(asList.size() - 1);
            }
        }
        return null;
    }

    private static String getOssParentPathFromUrl(String url) {
        if (!StringUtils.isEmpty(url)) {
            String pattern = ".com/";
            int i = url.indexOf(pattern);
            String substring = url.substring(pattern.length() + i);
            int i1 = substring.lastIndexOf("/");
            String substring1 = substring.substring(0, i1);
            return substring1;
        }
        return null;
    }

    private static void displayTextInputStream(InputStream input) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        while (true) {
            String line = reader.readLine();
            if (line == null) break;
        }
        reader.close();
    }

    /**
     * 格式化文件名
     *
     * @param fileName
     * @return
     */
    public static String buildFileName(String fileName) {
        String extName = fileName.substring(fileName.lastIndexOf("."));
        String newFileName = fileName.substring(0, fileName.lastIndexOf("."));

        newFileName = newFileName.replaceAll("[\\W&&[^\\u4E00-\\u9FA5]]", "-");
        newFileName = newFileName.replaceAll("-{2,}", "-");
        //newFileName = newFileName.toLowerCase();
        if (newFileName.endsWith("-")) {
            newFileName = newFileName.substring(0, newFileName.length() - 1);
        }
        newFileName = newFileName + extName;
        return newFileName;
    }


    /**
     * 获取文件的inputStream
     *
     * @param objectName 文件的oss路径
     */
    public static InputStream downloadFileInputStream(String objectName) {
        OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, objectName));
        return ossObject.getObjectContent();
    }

//    public static void close() {
//        if (ossClient != null) {
//            ossClient.shutdown();
//        }
//    }

    private static String getObjectKeyFromUrl(String url) {
        return url.substring(url.indexOf(endpoint) + endpoint.length() + 1 + bucketName.length() + 2);
    }

    private static String getFileNameFromObjectName(String objectName) {
        String[] pathSegments = objectName.split("/");
        return pathSegments[pathSegments.length - 1];
    }

    public static FileUrlData parseUrl(String url) {
        FileUrlData fileUrlData = new FileUrlData();
        String objectName = getObjectKeyFromUrl(url);
        String fileName = getFileNameFromObjectName(objectName);
        fileUrlData.setFileName(fileName);
        fileUrlData.setFileOssUrl(objectName);
        return fileUrlData;
    }

    /**
     * 列举 指定路径下所有的文件夹的文件名
     * 如果要列出根路径下的所有文件夹，path= ""
     *
     * @param path 路径
     * @return 文件夹
     */
    public static List<String> listFolderName(String path) {
        // 创建 OSS 客户端
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 构造ListObjectsRequest请求。
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
        // 设置prefix参数来获取指定路径下的所有文件。
        listObjectsRequest.setPrefix(path);
        listObjectsRequest.withDelimiter("/");
        // 遍历所有文件夹
        List<String> res = new ArrayList<>();
        ObjectListing objectListing;
        do {
            objectListing = ossClient.listObjects(listObjectsRequest);
            // 处理获取到的文件夹
            List<String> commonPrefixes = objectListing.getCommonPrefixes();
            res.addAll(commonPrefixes);
            // 设置下一次列举的起点
            listObjectsRequest.setMarker(objectListing.getNextMarker());
        } while (objectListing.isTruncated());
        // 关闭 OSS 客户端
        ossClient.shutdown();
        return res;
    }


    /**
     * 列举 指定路径下所有的文件夹的文件名
     * 如果要列出根路径下的所有文件夹，path= ""
     *
     * @param path
     * @return
     */
    public static List<String> listFileName(String path) {
        List<String> res = new ArrayList<>();
        // 构造ListObjectsRequest请求。
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);

        // 设置prefix参数来获取fun目录下的所有文件。
        listObjectsRequest.setPrefix(path);

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 列出文件。
        ObjectListing listing = ossClient.listObjects(listObjectsRequest);
        // 遍历所有文件
        for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
            res.add(objectSummary.getKey());
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return res;
    }
}
